<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="./vue.js"></script>
  <!-- <script src="./vue@2.6.js"></script> -->
  <title>Document</title>
</head>

<body>

  <div>
    <p>
      观察者模式--即每个属性都有一个dep（依赖），每次属性变化都会触发对应的watcher更新
    </p>
    <ul style="padding: 24px; font-weight: 700; background-color: rgb(214, 214, 214);">
      <p>
        在new Vue的时候拿到模板的字符串进行分析得到ast语法树，再转化为render函数，(调用后生成虚拟dom)，封装在wacther内部
      </p>
      <p>
        此时进行组件挂载，一个视图一个Watcher，new Watcher后会(调用update render)，刚好前一步给dep.target赋值对应的watcher，紧接着就直接调用render
      </p>
      <p>
        再render中_s(var) 会根据with(this)来直接在取值var, 所以自然取到了代理的对象上吗,调用了之前代理定义的get方法
      </p>
      <p>
        在get方法内进行判断dep.target即当前是否又Watcher即是否正在进行渲染视图(render函数的调用), 如果进来此分支就说明是渲染视图所需的
      </p>
      <p>
        即在dom的{{}}内定义的，此时才会收集依赖，收集的依赖在set（更改属性的时候进行调用）时，此时对dep（属性的依赖）通知存储所有的Watcher进行重新渲染
      </p>
      <p>
        对应的各个组件（每个组件一个Watcher）都会更新dom
      </p>
      <p>
        如此如果没有进入到dep.target的分支内说明没有收集依赖，此时的变量定义了也没有再模板{{}}上使用，此时对应属性的依赖(dep)内的存储的Watcher数量为0，不会触发渲染
      </p>
      <p>
        如此实现了只有在模板上引用的时候才会进行渲染更新
      </p>
    </ul>
    <hr />
    <div style="padding: 24px; font-weight: 700; background-color: rgb(167, 167, 167);">
      <p>
        注意nextTick并不是全部异步的，如果我把nextTick放在触发set操作前，那么此时nextTick的回调队列中取dom会先执行，此后再排队到更新dom,
        此时取值也是旧的dom值
      </p>
      <p>
        注意，当Watcher更新视图时，同步需要触发更新的wacther都缓存到队列里，异步方法内统一执行，这就是按批次执行更新视图
      </p>
      <p>
        为什么需要配一个nextTick？主要的原因就是需要统一异步的方法，因为异步还有区分微任务和宏任务
      </p>
      <p>
        如下如果我把nextTick内部的异步改成使用setTimeout, 那么此时，拿不到最新的dom，因为先走的时微任务，此后才会走宏任务_update(_render)更新dom
      </p>
      <p>
        而且有些浏览器不兼容Promise，此时需要一个公用的方法，而且能够兼容各个浏览器，也就是nextTick来统一异步批次更新的方法，而且自动降级匹配当前浏览器合适的方法
      </p>
      </p>
    </div>
  </div>

  <!-- 目前没有写匹配注释的东西，注释会出问题 -->
  <div style="color: rgb(131, 0, 0); height: 100%;" id="app">
    <div style="background-color: rgb(189, 189, 189); padding: 10px;" key="125">{{ jj }} {{ fqmyysjjd }} {{ jj }}</div>
    <div id="fqm" style="background-color: rgb(133, 133, 133); padding: 10px;" key="12315">{{ fqm }}</div>
    <div style="background-color: rgb(102, 102, 102); padding: 10px;">{{ fqmyysjjd }}</div>
  </div>

</body>

<!-- dom在script前 -->
<script>
  let vm = new Vue({
    data() {
      return {
        fqmyysjjd: ['yy', 'wqx', 'ysys'],
        jj: {
          fqm: 'zwfqmdqb',
          nw: 'yyfqm'
        },
        fqm: "fqmyysjjd",
        yy: "yysjjd",
      }
    },
    el: "#app"
  })

  // 在new Vue的时候拿到模板的字符串进行分析得到ast语法树，再转化为render函数，(调用后生成虚拟dom)，封装在wacther内部
  // 此时进行组件挂载，一个视图一个Watcher，new Watcher后会(调用update render)，刚好前一步给dep.target赋值对应的watcher，紧接着就直接调用render
  // 再render中_s(var) 会根据with(this)来直接在取值var, 所以自然取到了代理的对象上吗,调用了之前代理定义的get方法
  // 在get方法内进行判断dep.target即当前是否又Watcher即是否正在进行渲染视图(render函数的调用), 如果进来此分支就说明是渲染视图所需的
  // 即在dom的{{}}内定义的，此时才会收集依赖，收集的依赖在set（更改属性的时候进行调用）时，此时对dep（属性的依赖）通知存储所有的Watcher进行重新渲染
  // 对应的各个组件（每个组件一个Watcher）都会更新dom
  // 如此如果没有进入到dep.target的分支内说明没有收集依赖，此时的变量定义了也没有再模板{{}}上使用，此时对应属性的依赖(dep)内的存储的Watcher数量为0，不会触发渲染
  // 如此实现了只有在模板上引用的时候才会进行渲染更新


  // 在模板上没有取到yy的值所以不会进行依赖收集，不会绑定到watcher，但是定义了dep，所有有个空的subs数组
  // 当修改yy时触发set方法，dep（依赖）通知对应的watcher重新进行进行渲染，即重新_update(_render)
  console.log(vm.yy = 'fqmyysjjd!!!', "没有触发Watcher的update方法即更新视图的方法")

  setTimeout(() => {
    console.log(vm.fqm = "fqmyysjjd!!!", "触发Watcher的update方法即更新视图的方法")
  }, 1000);

  // 注意nextTick并不是全部异步的，如果我把nextTick放在触发set操作前，那么此时nextTick的回调队列中取dom会先执行，此后再排队到更新dom
  // 此时取值也是旧的dom值
  vm.$nextTick(() => {
    console.log(document.querySelector("#fqm").innerHTML)
  })
  vm.fqm = 'yysjjd'
  console.log(document.querySelector("#fqm").innerHTML)
  vm.$nextTick(() => {
    console.log(document.querySelector("#fqm").innerHTML)
  })
  // 注意，当Watcher更新视图时，同步需要触发更新的wacther都缓存到队列里，异步方法内统一执行，这就是按批次执行更新视图
  // 为什么需要配一个nextTick？主要的原因就是需要统一异步的方法，因为异步还有区分微任务和宏任务
  // 如下如果我把nextTick内部的异步改成使用setTimeout，那么此时，拿不到最新的dom，因为先走的时微任务，此后才会走宏任务_update(_render)更新dom
  // 而且有些浏览器不兼容Promise，此时需要一个公用的方法，而且能够兼容各个浏览器，也就是nextTick来统一异步批次更新的方法，
  // 而且自动降级匹配当前浏览器合适的方法
  Promise.resolve().then(() => {
    console.log(document.querySelector("#fqm").innerHTML)
  })


</script>

</html>

<style>
  html {
    height: 100%;
  }

  body {
    height: 100%;
  }
</style>